#encoding=utf-8
import hashlib
from random import Random

import datetime
import time
import requests
import simplejson
import urllib
import logging

log = logging.getLogger('django')

class APIError(object):
    def __init__(self, code, msg):
        self.code = code
        self.msg = msg

def wx_log_error(APIError):
    log.error('wechat api error: [%s], %s' % (APIError.code, APIError.msg))

def random_str(randomlength=8):
    str = ''
    chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789'
    length = len(chars) - 1
    random = Random()
    for i in range(randomlength):
        str+=chars[random.randint(0, length)]
    return str

class WechatBaseApi(object):

    API_PREFIX = u'https://api.weixin.qq.com/cgi-bin/'

    def __init__(self, appid, appsecret, token, api_entry=None):
        self.appid = appid
        self.appsecret = appsecret
        self.token = token
        self._access_token = None
        self._jsapi_ticket = None
        self.api_entry = api_entry or self.API_PREFIX

    def get_access_token(self, url=None, **kwargs):
        params = {'grant_type': 'client_credential', 'appid': self.appid, 'secret': self.appsecret}

        if kwargs:
            params.update(kwargs)
        print "url", url or self.api_entry + 'token'
        print "params", params
        rsp = requests.get(url or self.api_entry + 'token', params=params)
        print "rsp", rsp
        return self._process_response(rsp)

    @property
    def access_token(self):
        if not self._access_token:
            print "begin get access token"
            token, err = self.get_access_token()
            print "token", token
            if not err:
                self._access_token = token['access_token']
                self._access_token_expired_in = token['expires_in'];
                return self._access_token
            else:
                return None

        return self._access_token

    def get_jsapi_ticket(self):
        url = u'https://api.weixin.qq.com/cgi-bin/ticket/getticket'
        params ={
            'access_token':self.access_token,
            'type':'jsapi'
        }
        return self._process_response(requests.get(url, params=params))

    @property
    def jsapi_ticket(self):
        if not self._jsapi_ticket:
            print "begin get jsapi ticket"
            jsapi_ticket, err = self.get_jsapi_ticket()
            print "jsapi_ticket", jsapi_ticket
            if not err:
                self._jsapi_ticket = jsapi_ticket['ticket']
                self._jsapi_ticket_expired_in = jsapi_ticket['expires_in'];
                return self._jsapi_ticket
            else:
                return None

        return self._jsapi_ticket
    # 解析微信返回的json数据，返回相对应的dict
    def _process_response(self, rsp):
        print "enter _process_response"
        if 200 != rsp.status_code:
            return None, APIError(rsp.status_code, 'http error')
        try:
            content = rsp.json()
            print "content", content

        except Exception:
            return None, APIError(9999, 'invalid response')
        if 'errcode' in content and content['errcode'] != 0:
            return None, APIError(content['errcode'], content['errmsg'])

        print "content", content
        return content, None

    def check_signature(self, signature, timestamp, nonce):
        """
        验证微信消息真实性
        :param signature: 微信加密签名
        :param timestamp: 时间戳
        :param nonce: 随机数
        :return: 通过验证返回 True, 未通过验证返回 False
        """
        if not signature or not timestamp or not nonce:
            return False

        tmp_list = [self.token, timestamp, nonce]
        tmp_list.sort()
        tmp_str = ''.join(tmp_list)
        if signature != hashlib.sha1(tmp_str.encode('utf-8')).hexdigest():
            return False

        return True

    def _get(self, path, params=None):
        if not params:
            params = {}

        params['access_token'] = self.access_token

        rsp = requests(self.api_entry + path, params=params)

        return self._process_response(rsp)


    def _post(self, path, data, type='json'):

        header = {'content-type': 'application/json'}

        if '?' in path:
            url = self.api_entry + path + 'access_token=' + self.access_token
        else:
            url = self.api_entry + path + '?' + 'access_token=' + self.access_token

        if 'json' == type:
            data = simplejson.dumps(data, ensure_ascii=False).encode('utf-8')
        print 'data_json', data
        print 'url', url
        rsp = requests.post(url, data, headers=header)

        return self._process_response(rsp)

class WechatApi(WechatBaseApi):

    #返回授权url
    def auth_url(self, redirect_uri, scope='snsapi_userinfo', state=None):
        url = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect' % \
              (self.appid, urllib.quote(redirect_uri), scope, state if state else '')
        return url

   # 获取网页授权的access_token
    def get_auth_access_token(self, code):
        url = u'https://api.weixin.qq.com/sns/oauth2/access_token'
        params = {
            'appid': self.appid,
            'secret': self.appsecret,
            'code': code,
            'grant_type': 'authorization_code'
        }

        return self._process_response(requests.get(url, params=params))

    # 获取用户信息
    def get_user_info(self, auth_access_token, openid):
        url = u'https://api.weixin.qq.com/sns/userinfo?'
        params = {
            'access_token': auth_access_token,
            'openid': openid,
            'lang': 'zh_CN'
        }

        return self._process_response(requests.get(url, params=params))

    #通过openid获取用户在当前devicetype下绑定的deviceid列表。
    def get_bind_device(self, openid):
        url = u'https://api.weixin.qq.com/device/get_bind_device'
        print "url", url
        params={
            'access_token':self.access_token,
            'openid':openid
        }
        print "params", params
        return self._process_response(requests.get(url, params=params))

    #设备状态查询:第三方公众账号通过设备id查询该id的状态（三种状态：未授权、已授权、已绑定）。
    def get_device_status(self, deviceid):
        url = u'https://api.weixin.qq.com/device/get_stat'
        params={
            'access_token':self.access_token,
            'device_id':deviceid
        }
        return self._process_response(requests.get(url, params=params))

    def create_menu(self, menus):
        return self._post('menu/create', menus)

    def calc_wx_config(self, request):
        noncestr = random_str(16);
        timestamp = int(time.mktime(datetime.datetime.now().timetuple()))
        url = 'http://wxtest.mo-image.com'+ request.get_full_path()
        tmp_list = ['noncestr='+noncestr,
                    'jsapi_ticket=' + self.jsapi_ticket,
                    'timestamp=' + str(timestamp),
                    'url=' +url]
        tmp_list.sort()
        tmp_str = '&'.join(tmp_list)
        print "temp_string for signature:", tmp_str
        signature = hashlib.sha1(tmp_str.encode('utf-8')).hexdigest()
        return {
            'timestamp': timestamp,
            'nonceStr' : noncestr,
            'signature': signature,
            'url':url
            }

    def send_transmsg(self, device_type, device_id, open_id, content):
        url = 'https://api.weixin.qq.com/device/transmsg?access_token=%s' % self.access_token;
        params={
            "device_type": device_type,
            "device_id": device_id,
            "open_id": open_id,
            "content": content
        }
        header = {'content-type': 'application/json'}

        data = simplejson.dumps(params, ensure_ascii=False).encode('utf-8')

        print 'data_json', data
        print 'url', url
        rsp = requests.post(url, data, headers=header)
        print "response:", rsp.content
        return self._process_response(rsp)